using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.DirectoryServices.Protocols;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using OracleInternal.Common;
using OracleInternal.Secure.Network;

namespace OracleInternal.Network
{
	internal class LdapConfig
	{
		internal enum DirectoryServerTypes
		{
			AD,
			OID,
			UNKNOWN
		}

		internal static string DIRECTORY_SERVERS = "DIRECTORY_SERVERS";

		internal static string DIRECTORY_SERVER_TYPE = "DIRECTORY_SERVER_TYPE";

		internal static string DEFAULT_ADMIN_CONTEXT = "DEFAULT_ADMIN_CONTEXT";

		internal static string CONTEXT_MAP = "CONTEXT_MAP";

		private static string ACTIVE_DIRECTORY_TYPE = "AD";

		private static string OID_TYPE = "OID";

		private static int DefaultPort = 389;

		private static int DefaultSslPort = 636;

		private static char[] charsToTrim = new char[2]
		{
			'\\',
			'"'
		};

		private static string DCEQUALS = "dc=";

		private static string CEQUALS = "c=";

		private static string OEQUALS = "o=";

		private static string DIRECTORY_SERVERS_ERROR = "DIRECTORY_SERVERS parameter has error.";

		private static string DIRECTORY_SERVER_TYPE_ERROR = "DIRECTORY_SERVER_TYPE specified unknown type.";

		private static string WALLET_LOCATION_ERROR = "Wallet location is invalid.";

		private static string CERTIFICATE_ERROR = "No certificate found.";

		private List<LdapDirectoryIdentifier> m_LdapDirectoryIdentifiers;

		private AuthType m_AuthType;

		private NetworkCredential m_Credential;

		private X509CertificateCollection m_X509Collection;

		private bool m_SSL;

		private DirectoryServerTypes m_DirectoryServerType;

		private bool m_bDirectoryType_accessed;

		private bool m_WithC;

		private bool m_WithO;

		private bool m_WithDC;

		private bool m_DACparsed;

		private bool m_bDefaultAdminContext_accessed;

		private string m_DefaultAdminContext;

		private Hashtable m_LDAPconfigParameters;

		private SqlNetOraConfig m_SNOConfig;

		internal SqlNetOraConfig SNOConfig => m_SNOConfig;

		internal Hashtable LDAPconfigParameters => m_LDAPconfigParameters;

		internal string DirectoryServers => m_LDAPconfigParameters[DIRECTORY_SERVERS] as string;

		internal string DefaultAdminContext
		{
			get
			{
				if (!m_bDefaultAdminContext_accessed)
				{
					string text = m_LDAPconfigParameters[DEFAULT_ADMIN_CONTEXT] as string;
					m_DefaultAdminContext = ((!string.IsNullOrEmpty(text)) ? text.Trim(charsToTrim) : null);
					m_bDefaultAdminContext_accessed = true;
				}
				return m_DefaultAdminContext;
			}
		}

		internal DirectoryServerTypes DirectorySeverType
		{
			get
			{
				if (!m_bDirectoryType_accessed)
				{
					string text = (string)m_LDAPconfigParameters[DIRECTORY_SERVER_TYPE];
					m_DirectoryServerType = ((string.IsNullOrEmpty(text) || string.Compare(text, OID_TYPE, ignoreCase: true) == 0) ? DirectoryServerTypes.OID : ((string.Compare(text, ACTIVE_DIRECTORY_TYPE, ignoreCase: true) != 0) ? DirectoryServerTypes.UNKNOWN : DirectoryServerTypes.AD));
					m_bDirectoryType_accessed = true;
				}
				return m_DirectoryServerType;
			}
		}

		internal List<LdapDirectoryIdentifier> LdapDirectoryIdentifiers => m_LdapDirectoryIdentifiers;

		internal AuthType Authtype => m_AuthType;

		internal NetworkCredential Credential => m_Credential;

		internal X509CertificateCollection X509Collection => m_X509Collection;

		internal bool useSSL => m_SSL;

		internal bool DACwithC
		{
			get
			{
				if (!m_DACparsed)
				{
					ParseDAC();
				}
				return m_WithC;
			}
		}

		internal bool DACwithO
		{
			get
			{
				if (!m_DACparsed)
				{
					ParseDAC();
				}
				return m_WithO;
			}
		}

		internal bool DACwithDC
		{
			get
			{
				if (!m_DACparsed)
				{
					ParseDAC();
				}
				return m_WithDC;
			}
		}

		internal LdapConfig()
		{
			string text = ProviderConfig.NewOraFileLoc(OraFiles.Ldap);
			if (text.Length > 0)
			{
				if (ProviderConfig.m_bTraceLevelNetwork)
				{
					_trace("Reading LDAP.ORA from " + text + ".");
				}
				ProviderConfig.NewOraFileParams(OraFiles.Ldap, text, ConfigBaseClass.m_LDAPconfigParameters);
			}
			_LdapConfig(new SqlNetOraConfig(ConfigBaseClass.m_configParameters), ConfigBaseClass.m_LDAPconfigParameters);
			if (LdapDirectoryIdentifiers != null && LdapDirectoryIdentifiers.Count > 0)
			{
				ParseDAC();
				_ = DirectorySeverType;
				_ = DefaultAdminContext;
				if (ProviderConfig.m_bTraceLevelNetwork)
				{
					_trace("Created a LdapConfig object based on static configurations.");
				}
			}
		}

		internal LdapConfig(SqlNetOraConfig SNOConfig, Hashtable ObLdapHT)
		{
			_LdapConfig(SNOConfig, ObLdapHT);
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				_trace("Created a LdapConfig object based on new configurations.");
			}
		}

		internal void _LdapConfig(SqlNetOraConfig SNOConfig, Hashtable ObLdapHT)
		{
			m_bDirectoryType_accessed = false;
			m_DACparsed = false;
			if (SNOConfig == null || ObLdapHT == null)
			{
				if (ProviderConfig.m_bTraceLevelNetwork)
				{
					_trace("Invalid parameter passed.");
				}
				m_LdapDirectoryIdentifiers = null;
				m_Credential = null;
				return;
			}
			m_SNOConfig = SNOConfig;
			m_LDAPconfigParameters = ObLdapHT;
			try
			{
				_LdapConfig1();
			}
			catch (Exception ex)
			{
				if (ProviderConfig.m_bTraceLevelNetwork)
				{
					_trace(ex.ToString());
				}
				m_LdapDirectoryIdentifiers = null;
				m_Credential = null;
			}
		}

		private void ParseDAC()
		{
			string defaultAdminContext = DefaultAdminContext;
			if (!string.IsNullOrEmpty(defaultAdminContext))
			{
				string[] array = defaultAdminContext.Split(new char[1]
				{
					','
				});
				int num = array.Length - 1;
				array[num] = array[num].ToLowerInvariant();
				array[num] = array[num].Replace(" ", null);
				if (array[num].IndexOf(DCEQUALS) == 0)
				{
					m_WithDC = true;
					m_WithC = (m_WithO = false);
				}
				else if (array[num].IndexOf(OEQUALS) == 0)
				{
					m_WithO = true;
					m_WithDC = (m_WithC = false);
				}
				else if (array[num].IndexOf(CEQUALS) == 0)
				{
					int num2 = num - 1;
					array[num2] = array[num2].ToLowerInvariant();
					array[num2] = array[num2].Replace(" ", null);
					if (array[num2].IndexOf(OEQUALS) == 0)
					{
						m_WithC = (m_WithO = true);
						m_WithDC = false;
					}
				}
			}
			m_DACparsed = true;
		}

		internal void Refresh()
		{
			try
			{
				m_bDirectoryType_accessed = false;
				m_WithDC = (m_WithO = (m_WithC = false));
				m_DACparsed = false;
				_LdapConfig1();
			}
			catch (Exception)
			{
				m_LdapDirectoryIdentifiers = null;
				m_Credential = null;
			}
		}

		private void _LdapConfig1()
		{
			LdapDirectoryIdentifier ldapDirectoryIdentifier = null;
			int result = 0;
			int result2 = 0;
			if (DirectorySeverType == DirectoryServerTypes.UNKNOWN)
			{
				ConfigError(DIRECTORY_SERVER_TYPE_ERROR);
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				_trace("LDAP server type is " + ((DirectorySeverType == DirectoryServerTypes.AD) ? ACTIVE_DIRECTORY_TYPE : OID_TYPE));
			}
			if (m_LdapDirectoryIdentifiers == null)
			{
				m_LdapDirectoryIdentifiers = new List<LdapDirectoryIdentifier>();
			}
			else
			{
				m_LdapDirectoryIdentifiers.Clear();
			}
			string text = m_LDAPconfigParameters[DIRECTORY_SERVERS] as string;
			if (!string.IsNullOrEmpty(text))
			{
				if ((text[0] == '(') ^ (text[text.Length - 1] == ')'))
				{
					ConfigError(DIRECTORY_SERVERS_ERROR);
				}
				string text2 = ((text[0] == '(') ? text.Substring(1, text.Length - 2) : text);
				if (text2.Length > 0)
				{
					string[] array = text2.Split(new char[1]
					{
						','
					});
					for (int i = 0; i < array.Length; i++)
					{
						string[] array2 = array[i].Split(new char[1]
						{
							':'
						});
						if (array2.Length > 3)
						{
							ConfigError(DIRECTORY_SERVERS_ERROR);
						}
						if (array2.Length == 3 && ((!string.IsNullOrEmpty(array2[2]) && !int.TryParse(array2[2], out result2)) || (!string.IsNullOrEmpty(array2[1]) && !int.TryParse(array2[1], out result))))
						{
							ConfigError(DIRECTORY_SERVERS_ERROR);
						}
						if (array2.Length == 2 && !int.TryParse(array2[1], out result))
						{
							ConfigError(DIRECTORY_SERVERS_ERROR);
						}
						if (i == 0)
						{
							if ((array2.Length == 3 && string.IsNullOrEmpty(array2[1])) || (m_SNOConfig.NamesLdapAuthenticateBind && DirectorySeverType == DirectoryServerTypes.OID))
							{
								m_SSL = true;
							}
							else
							{
								m_SSL = false;
							}
						}
						int portNumber = ((!m_SSL) ? ((array2.Length > 1) ? result : DefaultPort) : ((array2.Length > 2) ? result2 : DefaultSslPort));
						try
						{
							IPAddress[] hostAddresses = Dns.GetHostAddresses(array2[0]);
							if (hostAddresses.Length == 0)
							{
								continue;
							}
							for (int j = 0; j < hostAddresses.Length; j++)
							{
								try
								{
									ldapDirectoryIdentifier = new LdapDirectoryIdentifier(hostAddresses[j].ToString(), portNumber, fullyQualifiedDnsHostName: false, connectionless: false);
									m_LdapDirectoryIdentifiers.Add(ldapDirectoryIdentifier);
									if (ProviderConfig.m_bTraceLevelNetwork)
									{
										_trace("added " + array2[0] + " using " + hostAddresses[j].ToString());
									}
								}
								catch (Exception)
								{
								}
							}
						}
						catch (Exception)
						{
						}
					}
				}
				else
				{
					ADorOIDdiscovery();
				}
			}
			else
			{
				ADorOIDdiscovery();
			}
			if (m_LdapDirectoryIdentifiers.Count <= 0)
			{
				return;
			}
			m_Credential = null;
			if (m_SNOConfig.NamesLdapAuthenticateBind)
			{
				if (ProviderConfig.m_bTraceLevelNetwork)
				{
					_trace("setting up authenticated bind to LDAP server");
				}
				if (DirectorySeverType == DirectoryServerTypes.OID)
				{
					Hashtable HT = null;
					string Dir = null;
					string text3 = null;
					string WP = null;
					X509Certificate2 x509Certificate = null;
					m_AuthType = AuthType.External;
					SqlNetOraConfig.GetWalletLoc(null, m_SNOConfig, out Dir, out HT);
					if (!string.IsNullOrEmpty(Dir))
					{
						text3 = "FILE";
					}
					else if (HT != null)
					{
						text3 = ((string)HT["METHOD"]).ToUpperInvariant();
						if (text3 != null && text3 == "FILE")
						{
							Dir = (string)HT["DIRECTORY"];
						}
					}
					if (ProviderConfig.m_bTraceLevelNetwork)
					{
						_trace("Wallet Location = " + Dir);
					}
					if (text3 == "FILE")
					{
						if (string.IsNullOrEmpty(Dir))
						{
							ConfigError(WALLET_LOCATION_ERROR);
						}
						x509Certificate = new X509Certificate2(WalletReader.ReadWallet(Dir, ref WP), WP, X509KeyStorageFlags.DefaultKeySet);
						m_X509Collection = new X509CertificateCollection(new X509Certificate[1]
						{
							x509Certificate
						});
					}
					else if (text3 == "MCS")
					{
						X509Store x509Store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
						x509Store.Open(OpenFlags.ReadOnly);
						m_X509Collection = x509Store.Certificates;
					}
					if (m_X509Collection == null || m_X509Collection.Count == 0)
					{
						ConfigError(CERTIFICATE_ERROR);
					}
				}
				else
				{
					m_AuthType = AuthType.Negotiate;
				}
			}
			else
			{
				m_AuthType = AuthType.Anonymous;
			}
		}

		private void ConfigError(string errMsg)
		{
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				string text = new StackFrame(1).GetMethod()!.Name + "(): " + errMsg;
				OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.None, OracleTraceClassName.LdapConfig, OracleTraceFuncName.ConfigError, text);
			}
			if (m_LdapDirectoryIdentifiers != null)
			{
				m_LdapDirectoryIdentifiers.Clear();
			}
			throw new Exception(errMsg);
		}

		private void _trace(string msg)
		{
			string text = new StackFrame(1).GetMethod()!.Name + "(): " + msg;
			OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Sqlnet, OracleTraceClassName.LdapConfig, OracleTraceFuncName._trace, text);
		}

		private void ADorOIDdiscovery()
		{
			m_LdapDirectoryIdentifiers.Clear();
			if (DirectorySeverType == DirectoryServerTypes.AD)
			{
				LdapDirectoryIdentifier item = new LdapDirectoryIdentifier(null);
				if (ProviderConfig.m_bTraceLevelNetwork)
				{
					_trace("Set to use default AD server");
				}
				m_LdapDirectoryIdentifiers.Add(item);
				return;
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				_trace("OID discovery is not available");
			}
			throw new NotImplementedException();
		}
	}
}
